"""
观察者模式应用比较广泛，又被称为“发布-订阅”模式。它用来定义对象间一种一对多的依赖关系，当一个对象的状态发生变化时，所有依赖它的对象都得到通知并被自动更新。

角色：
    抽象主题（Subject）
    具体主题（ConcreteSubject） -- 发布者
    抽象观察者（Observer）
    具体观察者（ConcreteObserver） -- 订阅者(观察者)

其实就是：
    1、创建一个发布者容器，把订阅者使用attach()放到容器中，通过遍历的方式推送消息
"""
from abc import abstractmethod, ABCMeta


# 抽象观察者（Observer）抽象订阅者
class Observer(metaclass=ABCMeta):
    """"""

    @abstractmethod
    def update(self, notice):
        pass


# 抽象主题（Subject） 抽象发布者：可以是接口，子类不需要实现，所以不需要定义抽象方法！
class Notice:
    def __init__(self):
        self.observer = []

    def attach(self, obj):
        # 将对象添加到列表
        self.observer.append(obj)

    def detach(self, obj):
        # 将对象从列表移除
        self.observer.remove(obj)

    def notify(self):
        """遍历对象列表推送消息"""
        for obj in self.observer:
            obj.update(self)


# 具体发布者
class StaffNotice(Notice):
    def __init__(self, company_info):
        super().__init__()  # 调用父类对象声明的observer属性
        self.__company_info = company_info

    @property
    def company_info(self):
        return self.__company_info

    @company_info.setter
    def company_info(self, info):
        self.__company_info = info
        self.notify()


# 具体的订阅者
class Staff(Observer):
    def __init__(self):
        self.company_info = None

    def update(self, notice):
        self.company_info = notice.company_info


staff_notice = StaffNotice('初始化公司信息')
staff1 = Staff()
staff2 = Staff()
staff_notice.attach(staff1)
staff_notice.attach(staff2)
staff_notice.company_info = '假期放假通知！'
print(staff1.company_info)
print(staff2.company_info)
staff_notice.detach(staff2)
staff_notice.company_info = '明天开会！'
print(staff1.company_info)
print(staff2.company_info)
